package constructdata;

import codetree.CodeTree;
import codetree.CodeTreeOperation;
import codetree.TreeNode;
import java.io.FileWriter;
import java.util.LinkedList;
import java.util.List;

/**
 * Termination Training Data Construction
 * Created by wangxin on 13/07/2017.
 */
public class ConstructTerminationData {
    // The marks
    private final String TERMMARK = "termination";
    // The construct trees
    private LinkedList<CodeTree> trees;
    // The predication holes correspondent to the constructTrees;
    private LinkedList<String> predications;
    // CodeTreeOperator
    private CodeTreeOperation operator;
    // The predicate node's complete class name
    private LinkedList<String> classnames;
    // The node who is the parent of the predicated one
    private LinkedList<TreeNode> parents;
    // The size of hole
    private  LinkedList<String> holesizes;

    /**
     * Constructor
     * */
    public ConstructTerminationData(){
        operator = new CodeTreeOperation();
    }

    /**
     * Construct training tree from the input code tree
     * */
    public void construct(CodeTree tree, String treePath, String predictionPath,String classPath,String generationNodePath, String treeSentencePath,String jarPath, String holeSizePath, boolean isCompleteFlag){
        LinkedList<LinkedList> result = getConstructTrainingData(tree);
        List<CodeTree> treeList = result.get(0);
        List<String> predictionList = result.get(1);
        List<String> classList = result.get(2);
        List<TreeNode> generationNodeList = result.get(3);
        List<String> holeSizeList = result.get(4);// record size of hole

        //FindJarHandler findJarHandler = new FindJarHandler();
        for (int i = 0; i < treeList.size(); i++) {
            try {
                //String jar = findJarHandler.getPackage(classList.get(i));
                //if(jar != null) {
                operator.saveRegularizedTreeInFile(operator.regularization(treeList.get(i)), treePath);
                operator.saveTrainingPredictionInFile(predictionList.get(i), predictionPath);
                operator.saveTrainingPredictionInFile(classList.get(i), classPath);
                //operator.saveTrainingPredictionInFile(jar, jarPath);
                int parentnum = generationNodeList.get(i).getSerialNumber();
                operator.saveTrainingPredictionInFile(parentnum + " " + ((parentnum != 0) ? generationNodeList.get(i).getCompleteMethodDeclaration() : ""), generationNodePath);
                operator.saveTreeStringFormatInFile(treeList.get(i), treeSentencePath, isCompleteFlag);

                operator.saveTrainingPredictionInFile(holeSizeList.get(i), holeSizePath);
                //}
            } catch (Exception e) {
                System.err.println(e.getMessage());
            }catch(Error e){
                System.err.println(e.getMessage());
            }
        }
    }

    public void construct(CodeTree tree,FileWriter treeWriter, FileWriter predictionWriter, FileWriter classWriter, FileWriter generationNodeWriter, FileWriter treeSentenceWriter, FileWriter jarWriter, FileWriter holeSizeWriter, boolean isCompleteFlag){
        LinkedList<LinkedList> result = getConstructTrainingData(tree);
        List<CodeTree> treeList = result.get(0);
        List<String> predictionList = result.get(1);
        List<String> classList = result.get(2);
        List<TreeNode> generationNodeList = result.get(3);
        List<String> holeSizeList = result.get(4);// record size of hole

        //FindJarHandler findJarHandler = new FindJarHandler();
        for (int i = 0; i < treeList.size(); i++) {
            try {
                //String jar = findJarHandler.getPackage(classList.get(i));
                //if(jar != null) {
                operator.saveRegularizedTreeInFile(operator.regularization(treeList.get(i)), treeWriter);
                operator.saveTrainingPredictionInFile(predictionList.get(i), predictionWriter);
                operator.saveTrainingPredictionInFile(classList.get(i), classWriter);
                //operator.saveTrainingPredictionInFile(jar, jarWriter);
                int parentnum = generationNodeList.get(i).getSerialNumber();
                operator.saveTrainingPredictionInFile(parentnum + " " + ((parentnum != 0) ? generationNodeList.get(i).getCompleteMethodDeclaration() : ""), generationNodeWriter);
                operator.saveTreeStringFormatInFile(treeList.get(i), treeSentenceWriter, isCompleteFlag);

                operator.saveTrainingPredictionInFile(holeSizeList.get(i), holeSizeWriter);

                //}
            } catch (Exception e) {
                System.err.println(e.getMessage());
            } catch (Error e){
                System.err.println(e.getMessage());
            }
        }
    }

    /**
     * Construct training tree from the input code tree
     * */
    public LinkedList<LinkedList> getConstructTrainingData(CodeTree completeTree){
        // Init
        trees = new LinkedList<>();
        predications = new LinkedList<>();
        classnames = new LinkedList<>();
        parents = new LinkedList<>();
        holesizes = new LinkedList<>();

        // Construct
        int count = completeTree.getTotalNumber();
        for (int i = 2; i <= count; i++) {// construct from the second node
            construct(completeTree, i);
        }

        // Return
        LinkedList<LinkedList> result = new LinkedList<>();
        result.addLast(trees);
        result.addLast(predications);
        result.addLast(classnames);
        result.addLast(parents);
        result.addLast(holesizes);

        return result;
    }

    /**
     * @param completeTree: training data from this tree
     * @param serialNumber: node to construct termination mark with this serial number
     * */
    private void construct(CodeTree completeTree, int serialNumber){
        // Make the replica of the completeTree to avoid destroying.
        CodeTree tree = new CodeTree();
        tree.copyCodeTree(completeTree);
        operator.setSerialNumberofEachNode(tree);

        if(tree.getTotalNumber() >= serialNumber){
            boolean isSuccess = true;
            TreeNode node = tree.getTreeNode(serialNumber);
            String label = node.getCompleteMethodDeclaration();
            if(tree.getTotalNumber() == 1){// root node.
                isSuccess = false;
            }
            else if(node.isCondition() // condition structure and conditions
                    || node.isControl()// if, else, elseif, for, foreach, while, switch
                    || label.equals("try")
                    || label.equals("catch")
                    || label.equals("condition")){
                isSuccess = false;
            }
            if(isSuccess){
                predications.addLast(TERMMARK);
                trees.addLast(tree);
                classnames.addLast(TERMMARK);
                parents.addLast(node);
                addHole(tree, node);
                holesizes.addLast("" + 0);
            }
        }
    }

    private void addHole(CodeTree tree, TreeNode generationNode) {
        TreeNode hole = new TreeNode();
        hole.setClassName("hole");
        hole.setCompleteClassName("hole");
        hole.setMethodName("");
        hole.setCompleteMethodName("");
        hole.setAddMethodName(false);
        tree.addNode(tree.getTreeNode(generationNode.getSerialNumber()), hole);
        operator.setSerialNumberofEachNode(tree);
    }
}
